package net.ozgul.chordmaster;

import java.util.ArrayList;
import java.util.List;

public enum Interval {
  
  
  /*
   * 
   0           Unison
   1           flat 2nd
   2           2nd
   3           minor 3rd
   4           major 3rd
   5           perfect 4th
   6           flat 5th (diminished 5th or augmented 4th)
   7           perfect 5th
   8           minor 6th  (or sharp 5th/augmented 5th)
   9           major 6th
  10           minor 7th  (flat 7th)
  11           major 7th
  12           octave
  13           flat 9th 
  14           9th
  15           sharp 9th/minor 10th (just minor 3rd one octave higher)
  16           major 10th (just major 3rd one octave higher)
  17           11th
  18           augmented 11th
  19           perfect 12th (octave above perfect 5th)
  20           flat 13th
  21           13th
*/
  UNISON(0), 
  FLATSECOND(2, -1),
  SECOND(2),
  SHARPSECOND(2, 1),
  MINORTHIRD(4, -1),
  MAJORTHIRD(4),
  SHARPTHIRD(4, 1),
  PERFECTFOURTH(5),
  AUGMENTEDFOURTH(5, 1),
  DIMINISHEDFIFTH(7, -1),
  FLATFIFTH(7, -1),
  PERFECTFIFTH(7),
  SHARPFIFTH(7, 1),
  AUGMENTEDFIFTH(7, 1),
  MINORSIXTH(9, -1),
  MAJORSIXTH(9),
  FLATSEVENTH(11, -1),
  MINORSEVENTH(11, -1),
  MAJORSEVENTH(11),
  OCTAVE(12),
  FLATNINTH(14, -1),
  NINTH(14),
  SHARPNINTH(14, 1),
  MINORTENTH(16, -1),
  MAJORTENTH(16),
  ELEVENTH(17),
  AUGMENTEDELEVENTH(17, 1),
  PERFECTTWELVTH(19),
  FLATTHIRTEENTH(21, -1),
  THIRTEENTH(21);
  
  private final int distanceFromRoot;
  private final int modification;
  
  /**
   * Each interval is related to a natural interval. For example flat second is related to second. 
   * Each interval is defined by how many semi-tones the relative natural interval is from 
   * the root note, and what modification to the natural interval is required to achieve 
   * this interval. For example a flat second interval is 1 semi-tone less than the second interval. 
   * 
   * This structure helps us distinguish between DSharp and EFlat, which have are at the same 
   * distance from the root note (C) but represent different intervals. 
   * 
   * @param distanceFromRoot the number of semi-tones that the relative interval is from the root. 
   * from the root not of a given scale.
   * @param modification the number of semi-tones to be applied to the natural interval to get
   * this interval.
   * 
   */
  private Interval(int distanceFromRoot, int modification) {
    this.distanceFromRoot = distanceFromRoot;
    this.modification = modification;
  }
  
  private Interval(int distanceFromRoot) {
    this(distanceFromRoot, 0);
  }
  
  int getDistanceFromRoot() {
    return distanceFromRoot + modification;
  }
  
  /**
   * Returns the list of all intervals which are at the same distance from the root note. 
   * 
   * @param distance the number of semi-tones that the intervals are apart from the root note
   * @return list of intervals with the given distance from the root note. 
   */
  static List<Interval> getIntervalsAtDistance(int distance) {
	  List<Interval> intervals = new ArrayList<Interval>();
	  for (Interval interval : Interval.values()) {
		  if (interval.getDistanceFromRoot() == distance) {
			  intervals.add(interval);
		  }
	  }
	  return intervals;
  }

  public int getNaturalDistanceFromRoot() {
    return distanceFromRoot;
  }

  public int getModification() {
    return modification;
  } 
}
